package com.wei.concurrent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * 一个自定义的布尔显式锁
 *
 * @author :sunwei
 * @description: 一个自定义的显式锁
 * @date create in 21:58  2021/6/16
 */
public class BooleanLock implements ExplicitLock {
    
    /* true:表示有线程占用锁
     * false:表示没有线程占用
     */
    private boolean flag;
    
    /* 记录被block的线程 */
    private List<Thread> blockedThreadList;
    
    /* 记录当前占用锁的线程,避免没有获取锁的线程调用unlock()将锁释放 */
    private Thread currentThread;
    
    public BooleanLock() {
        blockedThreadList = new ArrayList<>();
    }
    
    @Override
    public synchronized void lock() throws InterruptedException {
        while (flag) {
            blockedThreadList.add(Thread.currentThread());
            this.wait();
            blockedThreadList.remove(Thread.currentThread());
        }
        System.out.println(Thread.currentThread().getName() + "get this lock.");
        flag = true;
        currentThread = Thread.currentThread();
    }
    
    @Override
    public synchronized void lock(long mills) throws InterruptedException, TimeOutException {
        if (mills <= 0) {
            lock();
        } else {
            long remain = mills;
            long end = mills + System.currentTimeMillis();
            
            while (flag) {
                if (remain <= 0) {
                    throw new TimeOutException(Thread.currentThread().getName() + " is time out.");
                }
                blockedThreadList.add(Thread.currentThread());
                this.wait(mills);
                blockedThreadList.remove(Thread.currentThread());
                remain = end - System.currentTimeMillis();
            }
            System.out.println(Thread.currentThread().getName() + "get this lock.");
            flag = true;
            currentThread = Thread.currentThread();
        }
    }
    
    @Override
    public synchronized void unlock() {
        if (Thread.currentThread() == currentThread) {
            flag = false;
            System.out.println(Thread.currentThread().getName() + "release this lock.");
            this.notifyAll();
        } else {
            System.err.println("lock is not belong to you,you can't unlock this lock!");
        }
    }
    
    public List<Thread> getBlockedThreadList() {
        return Collections.unmodifiableList(blockedThreadList);
    }
}
